"""
基础券商接口

定义券商连接的基础接口和数据结构。
"""

import asyncio
import logging
from abc import ABC, abstractmethod
from datetime import datetime
from decimal import Decimal
from enum import Enum
from typing import Dict, List, Optional, Any, Callable
from dataclasses import dataclass, field


class BrokerType(Enum):
    """券商类型"""
    MOCK = "mock"                   # 模拟券商
    EASTMONEY = "eastmoney"         # 东方财富
    TONGHUASHUN = "tonghuashun"     # 同花顺
    GUOTAIJUNAN = "guotaijunan"     # 国泰君安
    HUATAI = "huatai"               # 华泰证券
    ZHONGXIN = "zhongxin"           # 中信证券
    SHENWAN = "shenwan"             # 申万宏源
    ZHAOSHANG = "zhaoshang"         # 招商证券
    PINGAN = "pingan"               # 平安证券
    CITIC = "citic"                 # 中信建投
    CUSTOM = "custom"               # 自定义


class OrderType(Enum):
    """订单类型"""
    MARKET = "market"               # 市价单
    LIMIT = "limit"                 # 限价单
    STOP = "stop"                   # 止损单
    STOP_LIMIT = "stop_limit"       # 止损限价单
    TRAILING_STOP = "trailing_stop" # 跟踪止损单


class OrderSide(Enum):
    """订单方向"""
    BUY = "buy"                     # 买入
    SELL = "sell"                   # 卖出


class OrderStatus(Enum):
    """订单状态"""
    PENDING = "pending"             # 待提交
    SUBMITTED = "submitted"         # 已提交
    PARTIAL_FILLED = "partial_filled" # 部分成交
    FILLED = "filled"               # 完全成交
    CANCELLED = "cancelled"         # 已撤销
    REJECTED = "rejected"           # 已拒绝
    EXPIRED = "expired"             # 已过期
    ERROR = "error"                 # 错误


@dataclass
class OrderRequest:
    """订单请求"""
    symbol: str                     # 证券代码
    side: OrderSide                 # 买卖方向
    order_type: OrderType           # 订单类型
    quantity: int                   # 数量
    price: Optional[Decimal] = None # 价格（限价单必填）
    stop_price: Optional[Decimal] = None # 止损价格
    time_in_force: str = "DAY"      # 有效期
    client_order_id: Optional[str] = None # 客户端订单ID
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'symbol': self.symbol,
            'side': self.side.value,
            'order_type': self.order_type.value,
            'quantity': self.quantity,
            'price': float(self.price) if self.price else None,
            'stop_price': float(self.stop_price) if self.stop_price else None,
            'time_in_force': self.time_in_force,
            'client_order_id': self.client_order_id
        }


@dataclass
class Order:
    """订单信息"""
    order_id: str                   # 订单ID
    client_order_id: Optional[str] # 客户端订单ID
    symbol: str                     # 证券代码
    side: OrderSide                 # 买卖方向
    order_type: OrderType           # 订单类型
    quantity: int                   # 委托数量
    price: Optional[Decimal]        # 委托价格
    stop_price: Optional[Decimal]   # 止损价格
    status: OrderStatus             # 订单状态
    filled_quantity: int = 0        # 成交数量
    avg_fill_price: Optional[Decimal] = None # 平均成交价格
    commission: Decimal = Decimal('0') # 手续费
    created_time: Optional[datetime] = None # 创建时间
    updated_time: Optional[datetime] = None # 更新时间
    error_message: Optional[str] = None # 错误信息
    
    def __post_init__(self):
        if self.created_time is None:
            self.created_time = datetime.now()
        if self.updated_time is None:
            self.updated_time = datetime.now()
    
    @property
    def remaining_quantity(self) -> int:
        """剩余数量"""
        return self.quantity - self.filled_quantity
    
    @property
    def is_filled(self) -> bool:
        """是否完全成交"""
        return self.status == OrderStatus.FILLED
    
    @property
    def is_active(self) -> bool:
        """是否活跃状态"""
        return self.status in [OrderStatus.PENDING, OrderStatus.SUBMITTED, OrderStatus.PARTIAL_FILLED]
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'order_id': self.order_id,
            'client_order_id': self.client_order_id,
            'symbol': self.symbol,
            'side': self.side.value,
            'order_type': self.order_type.value,
            'quantity': self.quantity,
            'price': float(self.price) if self.price else None,
            'stop_price': float(self.stop_price) if self.stop_price else None,
            'status': self.status.value,
            'filled_quantity': self.filled_quantity,
            'avg_fill_price': float(self.avg_fill_price) if self.avg_fill_price else None,
            'commission': float(self.commission),
            'created_time': self.created_time.isoformat() if self.created_time else None,
            'updated_time': self.updated_time.isoformat() if self.updated_time else None,
            'error_message': self.error_message
        }


@dataclass
class Trade:
    """成交记录"""
    trade_id: str                   # 成交ID
    order_id: str                   # 订单ID
    symbol: str                     # 证券代码
    side: OrderSide                 # 买卖方向
    quantity: int                   # 成交数量
    price: Decimal                  # 成交价格
    commission: Decimal             # 手续费
    timestamp: datetime             # 成交时间
    
    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = datetime.now()
    
    @property
    def total_amount(self) -> Decimal:
        """成交金额"""
        return Decimal(str(self.quantity)) * self.price
    
    @property
    def net_amount(self) -> Decimal:
        """净成交金额（扣除手续费）"""
        return self.total_amount - self.commission
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'trade_id': self.trade_id,
            'order_id': self.order_id,
            'symbol': self.symbol,
            'side': self.side.value,
            'quantity': self.quantity,
            'price': float(self.price),
            'commission': float(self.commission),
            'timestamp': self.timestamp.isoformat(),
            'total_amount': float(self.total_amount),
            'net_amount': float(self.net_amount)
        }


@dataclass
class Position:
    """持仓信息"""
    symbol: str                     # 证券代码
    quantity: int                   # 持仓数量
    avg_cost: Decimal               # 平均成本
    market_value: Decimal           # 市值
    unrealized_pnl: Decimal         # 未实现盈亏
    realized_pnl: Decimal = Decimal('0') # 已实现盈亏
    
    @property
    def total_pnl(self) -> Decimal:
        """总盈亏"""
        return self.unrealized_pnl + self.realized_pnl
    
    @property
    def pnl_percentage(self) -> Decimal:
        """盈亏百分比"""
        if self.avg_cost == 0:
            return Decimal('0')
        return (self.total_pnl / (Decimal(str(self.quantity)) * self.avg_cost)) * Decimal('100')
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'symbol': self.symbol,
            'quantity': self.quantity,
            'avg_cost': float(self.avg_cost),
            'market_value': float(self.market_value),
            'unrealized_pnl': float(self.unrealized_pnl),
            'realized_pnl': float(self.realized_pnl),
            'total_pnl': float(self.total_pnl),
            'pnl_percentage': float(self.pnl_percentage)
        }


@dataclass
class AccountInfo:
    """账户信息"""
    account_id: str                 # 账户ID
    total_value: Decimal            # 总资产
    available_cash: Decimal         # 可用现金
    market_value: Decimal           # 持仓市值
    buying_power: Decimal           # 购买力
    unrealized_pnl: Decimal         # 未实现盈亏
    realized_pnl: Decimal           # 已实现盈亏
    margin_used: Decimal = Decimal('0') # 已用保证金
    
    @property
    def total_pnl(self) -> Decimal:
        """总盈亏"""
        return self.unrealized_pnl + self.realized_pnl
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'account_id': self.account_id,
            'total_value': float(self.total_value),
            'available_cash': float(self.available_cash),
            'market_value': float(self.market_value),
            'buying_power': float(self.buying_power),
            'unrealized_pnl': float(self.unrealized_pnl),
            'realized_pnl': float(self.realized_pnl),
            'margin_used': float(self.margin_used),
            'total_pnl': float(self.total_pnl)
        }


@dataclass
class MarketData:
    """市场数据"""
    symbol: str                     # 证券代码
    last_price: Decimal             # 最新价
    bid_price: Optional[Decimal] = None # 买一价
    ask_price: Optional[Decimal] = None # 卖一价
    bid_size: Optional[int] = None  # 买一量
    ask_size: Optional[int] = None  # 卖一量
    volume: Optional[int] = None    # 成交量
    timestamp: Optional[datetime] = None # 时间戳
    
    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = datetime.now()
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'symbol': self.symbol,
            'last_price': float(self.last_price),
            'bid_price': float(self.bid_price) if self.bid_price else None,
            'ask_price': float(self.ask_price) if self.ask_price else None,
            'bid_size': self.bid_size,
            'ask_size': self.ask_size,
            'volume': self.volume,
            'timestamp': self.timestamp.isoformat() if self.timestamp else None
        }


class BaseBroker(ABC):
    """基础券商接口"""
    
    def __init__(self, broker_type: BrokerType, config: Dict[str, Any]):
        self.broker_type = broker_type
        self.config = config
        self.logger = logging.getLogger(f"{__name__}.{broker_type.value}")
        
        # 连接状态
        self.is_connected = False
        
        # 回调函数
        self.order_update_callback: Optional[Callable[[Order], None]] = None
        self.trade_callback: Optional[Callable[[Trade], None]] = None
        self.market_data_callback: Optional[Callable[[MarketData], None]] = None
        
        # 内部状态
        self._lock = asyncio.Lock()
    
    @abstractmethod
    async def connect(self) -> bool:
        """连接券商"""
        pass
    
    @abstractmethod
    async def disconnect(self):
        """断开连接"""
        pass
    
    @abstractmethod
    async def submit_order(self, order_request: OrderRequest) -> Order:
        """提交订单"""
        pass
    
    @abstractmethod
    async def cancel_order(self, order_id: str) -> bool:
        """撤销订单"""
        pass
    
    @abstractmethod
    async def get_order(self, order_id: str) -> Optional[Order]:
        """获取订单信息"""
        pass
    
    @abstractmethod
    async def get_orders(self, symbol: Optional[str] = None) -> List[Order]:
        """获取订单列表"""
        pass
    
    @abstractmethod
    async def get_trades(self, symbol: Optional[str] = None) -> List[Trade]:
        """获取成交记录"""
        pass
    
    @abstractmethod
    async def get_positions(self) -> List[Position]:
        """获取持仓信息"""
        pass
    
    @abstractmethod
    async def get_account_info(self) -> AccountInfo:
        """获取账户信息"""
        pass
    
    @abstractmethod
    async def get_market_data(self, symbol: str) -> Optional[MarketData]:
        """获取市场数据"""
        pass
    
    @abstractmethod
    async def subscribe_market_data(self, symbols: List[str]) -> bool:
        """订阅市场数据"""
        pass
    
    @abstractmethod
    async def unsubscribe_market_data(self, symbols: List[str]) -> bool:
        """取消订阅市场数据"""
        pass
    
    def set_order_update_callback(self, callback: Callable[[Order], None]):
        """设置订单更新回调"""
        self.order_update_callback = callback
    
    def set_trade_callback(self, callback: Callable[[Trade], None]):
        """设置成交回调"""
        self.trade_callback = callback
    
    def set_market_data_callback(self, callback: Callable[[MarketData], None]):
        """设置市场数据回调"""
        self.market_data_callback = callback
    
    async def _notify_order_update(self, order: Order):
        """通知订单更新"""
        if self.order_update_callback:
            try:
                self.order_update_callback(order)
            except Exception as e:
                self.logger.error(f"订单更新回调错误: {e}")
    
    async def _notify_trade(self, trade: Trade):
        """通知成交"""
        if self.trade_callback:
            try:
                self.trade_callback(trade)
            except Exception as e:
                self.logger.error(f"成交回调错误: {e}")
    
    async def _notify_market_data(self, market_data: MarketData):
        """通知市场数据"""
        if self.market_data_callback:
            try:
                self.market_data_callback(market_data)
            except Exception as e:
                self.logger.error(f"市场数据回调错误: {e}")
    
    def get_broker_info(self) -> Dict[str, Any]:
        """获取券商信息"""
        return {
            'broker_type': self.broker_type.value,
            'is_connected': self.is_connected,
            'config': {k: v for k, v in self.config.items() if k not in ['password', 'token', 'secret']}
        }